#ifndef __VM_FILE__
#define __VM_FILE__

#include "directory.h"
#include "volume.h"

namespace xm
{
	enum FileOpt
	{
		KF_BUILDIN	= 1,
		KF_PEFILE	= 2,
		KF_SHR		= 0x10000000,
		KF_SHW		= 0x20000000,
		KF_SHD		= 0x40000000,
	};


	class volm_file_t : public IKBStream, public MountableObject<KoFile>, UnkBase
	{
		typedef MountableObject<KoFile>	BaseT;
	protected:
		iptr<IKBStream>		data;
		optr<volume_t>		vol;
		uint32_t			opt;
	public:

		UNKNOWN_IMP2_(IKernelObject, IKBStream);

		volm_file_t() : opt(0)
		{

		}

		long get_win32_full_path( std::string & full );

		STDMETHOD(MountOn)(IKernelObject* k);

		HRESULT create( IUnknown * kbs, LPCSTR aname, uint32_t opts = 0 );

		VOID close();

		IKBStream * get_do();

		uint32_t get_opt();

		STDMETHOD_(BOOL,IsVirtual)() ;

		STDMETHOD(Read)( LPVOID lpBuffer, SIZE_T cbData, SIZE_T * lpEff );

		STDMETHOD(Write)( LPCVOID lpBuffer, SIZE_T cbData, SIZE_T * lpEff );

		STDMETHOD(Seek)( INT64 dist, SEEK_FORM from );

		STDMETHOD(Tell)( UINT64 * puliPointer );

		STDMETHOD(Readp)( UINT64 uliPos, LPVOID lpBuffer, SIZE_T cbData, SIZE_T * lpEff );

		STDMETHOD(Writep)( UINT64 uliPos, LPCVOID lpBuffer, SIZE_T cbData, SIZE_T * lpEff );

		STDMETHOD(SetPos)( UINT64 uliPos );

		STDMETHOD_(UINT64,Length)();

		STDMETHOD(Truncate)();

		STDMETHOD(Rollback)();
	};

	//////////////////////////////////////////////////////////////////////////

	class handle_file_t : public KernelObject<KoHandleFile>, UnkBase
	{
	public:

		optr<volm_file_t>	fo;
		uint64_t			ptr;
		
		UNKNOWN_IMP1(IKernelObject);

		handle_file_t() :	ptr(0)
		{}
		long seek( INT64 dist, SEEK_FORM from )
		{
			if( !fo ) return E_UNEXPECTED;

			if( from == SEEK_SET )
			{
				ptr = dist;
			}
			else if( from == SEEK_CUR )
			{
				ptr += dist;
			}
			else if( from == SEEK_END )
			{
				uint64_t fs = fo->Length();
				if( fs == LENGTH_ERROR ) return E_FAIL;
				ptr = fs + dist;
			}
			else
			{
				return E_INVALIDARG;
			}
			return S_OK;
		}
	};

};

#endif